'use client';

import { useState, useEffect, useCallback, useRef } from 'react';
import { useParams, useRouter } from 'next/navigation';
import { useAuth } from '@/lib/auth-context';
import { assetsApi, commentsApi, AssetWithComments, Asset, Comment, AnnotationData, TranscodeStatus } from '@/lib/api';
import { Avatar } from '@/components/ui/avatar';
import { VideoPlayer } from '@/components/video-player/VideoPlayer';
import { Tool } from '@/components/video-player/AnnotationCanvas';
import { formatTimecode } from '@/lib/format';

const API_BASE = process.env.NEXT_PUBLIC_API_URL || '';

const MAX_ANNOTATIONS = 10;

const STATUS_CONFIG: Record<string, { label: string; colorClass: string; bgClass: string; dotClass: string }> = {
  PENDING_REVIEW:    { label: 'Pending Review',    colorClass: 'text-warning', bgClass: 'badge-warning', dotClass: 'status-dot-pending' },
  CHANGES_REQUESTED: { label: 'Changes Requested', colorClass: 'text-warning', bgClass: 'badge-warning', dotClass: 'status-dot-changes' },
  APPROVED:          { label: 'Approved',          colorClass: 'text-success', bgClass: 'badge-success', dotClass: 'status-dot-approved' },
  REJECTED:          { label: 'Rejected',           colorClass: 'text-danger', bgClass: 'badge-danger',  dotClass: 'status-dot-rejected' },
};

const TRANSCODE_CONFIG: Record<TranscodeStatus, { label: string; color: string; bg: string; spinner: boolean }> = {
  PENDING:           { label: 'Queued',             color: '#94A3B8', bg: 'rgba(148,163,184,0.08)',  spinner: false },
  UPLOADING:         { label: 'Uploading video…',   color: '#60A5FA', bg: 'rgba(96,165,250,0.08)',   spinner: true  },
  PROCESSING:        { label: 'Transcoding…',      color: '#A78BFA', bg: 'rgba(167,139,250,0.08)',  spinner: true  },
  COMPLETED:         { label: 'Ready',              color: '#34D399', bg: 'rgba(52,211,153,0.08)',   spinner: false },
  FAILED:            { label: 'Transcode failed',   color: '#F87171', bg: 'rgba(248,113,113,0.08)',  spinner: false },
  UNSUPPORTED_CODEC: { label: 'Unsupported codec', color: '#FBBF24', bg: 'rgba(251,191,36,0.08)',   spinner: false },
};

export default function ReviewPage() {
  const params = useParams();
  const assetId = params.assetId as string;
  const { token, user } = useAuth();
  const router = useRouter();

  const [asset, setAsset] = useState<AssetWithComments | null>(null);
  const [comments, setComments] = useState<Comment[]>([]);
  const [loading, setLoading] = useState(true);
  const [currentTime, setCurrentTime] = useState(0);
  const [panelWidth, setPanelWidth] = useState(380);
  const [showApproval, setShowApproval] = useState(false);
  const [updatingStatus, setUpdatingStatus] = useState(false);
  const [newComment, setNewComment] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [replyTo, setReplyTo] = useState<Comment | null>(null);
  const [showResolved, setShowResolved] = useState(false);

  // Drawing state — lifted to page level
  const [drawMode, setDrawMode] = useState(false);
  const [drawTool, setDrawTool] = useState<Tool>('arrow');
  const [drawColor, setDrawColor] = useState('#ef4444');
  const [pendingStrokes, setPendingStrokes] = useState<AnnotationData[]>([]);
  // The comment we're annotating (null = annotating the main video, not a specific comment)
  const [annotatingComment, setAnnotatingComment] = useState<Comment | null>(null);

  // Portrait / landscape detection
  const [isPortrait, setIsPortrait] = useState(false);

  // ── Side-by-side compare mode ────────────────────────────────────────────
  const [compareMode, setCompareMode] = useState(false);
  const [compareAsset, setCompareAsset] = useState<Asset | null>(null);
  const [showComparePicker, setShowComparePicker] = useState(false);
  const [projectAssets, setProjectAssets] = useState<Asset[]>([]);
  const [compareMismatch, setCompareMismatch] = useState<string | null>(null);
  const [compareComments, setCompareComments] = useState<Comment[]>([]);
  const [playing, setPlaying] = useState(false);
  // Toggle annotation + speech bubble visibility per video in compare mode
  const [showMainAnnotations, setShowMainAnnotations] = useState(true);
  const [showCompareAnnotations, setShowCompareAnnotations] = useState(true);
  // Video element ref so we can seek directly from comment timestamp clicks
  const mainVideoRef = useRef<HTMLVideoElement>(null);

  const handleCompareSelect = useCallback((compareAssetArg: Asset) => {
    setShowComparePicker(false);
    setCompareMismatch(null);
    const dur1 = asset?.duration ?? 0;
    const dur2 = compareAssetArg.duration ?? 0;
    const fps = asset?.fps ?? compareAssetArg.fps ?? 30;
    const diffFrames = Math.abs(dur1 - dur2) * fps;
    if (diffFrames > 5) {
      setCompareMismatch(
        `Videos differ by ${Math.round(diffFrames)} frames. Cannot compare — timing mismatch.`
      );
      // Show mismatch banner but don't enter compare mode
      setCompareAsset(compareAssetArg);
      setCompareMode(true);
      return;
    }
    setCompareAsset(compareAssetArg);
    setCompareMode(true);
    // Fetch compare asset's own comments for per-video annotations
    if (token) {
      commentsApi.list(token, compareAssetArg.id).then(({ comments: cc }) => {
        setCompareComments(cc);
      }).catch(() => setCompareComments([]));
    }
  }, [asset, token]);

  const handleExitCompare = useCallback(() => {
    setCompareMode(false);
    setCompareAsset(null);
    setCompareMismatch(null);
    setCompareComments([]);
  }, []);

  useEffect(() => {
    const mq = window.matchMedia('(orientation: portrait)');
    setIsPortrait(mq.matches);
    const handler = (e: MediaQueryListEvent) => setIsPortrait(e.matches);
    mq.addEventListener('change', handler);
    return () => mq.removeEventListener('change', handler);
  }, []);

  const isDraggingRef = useRef(false);
  const panelRef = useRef<HTMLDivElement>(null);
  const resizeStartRef = useRef<{ x: number; w: number } | null>(null);
  // Ref to capture strokes for save callback (avoids closure stale value)
  const pendingStrokesRef = useRef<AnnotationData[]>([]);
  const annotatingCommentRef = useRef<Comment | null>(null);
  // Keep refs in sync with state
  useEffect(() => { pendingStrokesRef.current = pendingStrokes; }, [pendingStrokes]);
  useEffect(() => { annotatingCommentRef.current = annotatingComment; }, [annotatingComment]);

  const fps = asset?.fps ?? 30;

  // Derive the current user's project role
  const currentUserRole = asset?.project.members.find(m => m.user.id === user?.id)?.role;
  const isProjectAdmin = currentUserRole === 'ADMIN';
  const isProjectOwner = asset?.project.ownerId === user?.id;
  const canComment: boolean | undefined = !!(currentUserRole && currentUserRole !== 'VIEWER');

  // ── Poll for transcode progress ───────────────────────────────────────────
  const isTranscoding = asset?.transcodeStatus === 'COMPLETED';
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    if (isTranscoding) {
      if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; }
      return;
    }
    if (pollRef.current) return;
    pollRef.current = setInterval(async () => {
      if (!token) return;
      try {
        const { asset: updated } = await assetsApi.getStatus(token, assetId);
        setAsset(prev => prev ? { ...prev, ...updated } : prev);
      } catch {}
    }, 2000);
    return () => { if (pollRef.current) clearInterval(pollRef.current); };
  }, [token, assetId, isTranscoding]);

  // Load asset + comments
  const loadData = useCallback(async () => {
    if (!token) return;
    try {
      const [{ asset: a }, { comments: c }] = await Promise.all([
        assetsApi.get(token, assetId),
        commentsApi.list(token, assetId),
      ]);
      setAsset(a);
      setComments(c);
    } catch {
      router.push('/projects');
    } finally {
      setLoading(false);
    }
  }, [token, assetId, router]);

  useEffect(() => { loadData(); }, [loadData]);

  // ── Panel resize ─────────────────────────────────────────────────────────
  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!isDraggingRef.current || !resizeStartRef.current) return;
    const dx = e.clientX - resizeStartRef.current.x;
    setPanelWidth(Math.max(280, Math.min(600, resizeStartRef.current.w + dx)));
  }, []);

  const handleMouseUp = useCallback(() => {
    isDraggingRef.current = false;
    resizeStartRef.current = null;
    document.body.style.userSelect = '';
    document.body.style.cursor = '';
  }, []);

  useEffect(() => {
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
    };
  }, [handleMouseMove, handleMouseUp]);

  const handleResizeStart = (e: React.MouseEvent) => {
    e.preventDefault();
    isDraggingRef.current = true;
    resizeStartRef.current = { x: e.clientX, w: panelWidth };
    document.body.style.userSelect = 'none';
    document.body.style.cursor = 'col-resize';
  };

  // ── Comment actions ───────────────────────────────────────────────────────
  const handleAddComment = async (content: string, timestamp?: number, annotations?: AnnotationData[]) => {
    if (!token || !content.trim()) return;
    setSubmitting(true);
    try {
      const { comment } = await commentsApi.create(token, assetId, {
        content: content.trim(),
        timestamp,
        annotations,
        parentId: replyTo?.id,
      });
      if (replyTo) {
        setComments(prev => prev.map(c =>
          c.id === replyTo.id
            ? { ...c, replies: [...(c.replies ?? []), comment] }
            : c
        ));
      } else {
        setComments(prev => [...prev, comment]);
      }
      setNewComment('');
      setPendingStrokes([]);
      setReplyTo(null);
    } catch (err) {
      alert(err instanceof Error ? err.message : 'Failed to add comment');
    } finally {
      setSubmitting(false);
    }
  };

  const handleResolve = async (commentId: string, action: 'approve' | 'reject') => {
    if (!token) return;
    try {
      const { comment } = await commentsApi.resolve(token, commentId, action);
      setComments(prev => prev.map(c => c.id === commentId ? comment : c));
    } catch (err) {
      alert(err instanceof Error ? err.message : 'Failed to update comment');
    }
  };

  const handleRequestResolve = async (commentId: string) => {
    if (!token) return;
    try {
      const { comment } = await commentsApi.requestResolve(token, commentId);
      setComments(prev => prev.map(c => c.id === commentId ? comment : c));
    } catch (err) {
      alert(err instanceof Error ? err.message : 'Failed to request resolve');
    }
  };

  const handleDeleteComment = async (commentId: string) => {
    if (!token) return;
    // Soft delete — just mark hidden, owner can restore
    try {
      await commentsApi.delete(token, commentId);
      setComments(prev => prev.map(c =>
        c.id === commentId ? { ...c, deleted: true } : c
      ));
    } catch {
      alert('Failed to hide comment');
    }
  };

  const handleRestoreComment = async (commentId: string) => {
    if (!token) return;
    try {
      const { comment } = await commentsApi.restoreComment(token, commentId);
      setComments(prev => prev.map(c => c.id === commentId ? comment : c));
    } catch {
      alert('Failed to restore comment');
    }
  };

  // ── Annotation actions ─────────────────────────────────────────────────────
  // User clicks "Add annotation" on a comment — enter draw mode, annotate at current time
  const handleAddAnnotationClick = (comment: Comment) => {
    const existingCount = comment.annotations?.length ?? 0;
    if (existingCount >= MAX_ANNOTATIONS) {
      alert(`Maximum ${MAX_ANNOTATIONS} annotations per comment.`);
      return;
    }
    setPendingStrokes([]);
    setAnnotatingComment(comment);
    setDrawMode(true);
  };

  // Each completed stroke is added to pendingStrokes
  const handleStrokeComplete = (stroke: AnnotationData) => {
    setPendingStrokes(prev => {
      const next = [...prev, stroke];
      if (next.length >= MAX_ANNOTATIONS) {
        setDrawMode(false);
      }
      return next;
    });
  };

  // Save pending strokes as annotation on the parent comment (no separate reply)
  const handleSaveAnnotations = () => {
    const strokes = pendingStrokesRef.current;
    const parent = annotatingCommentRef.current;
    if (!token || !parent || strokes.length === 0) {
      setPendingStrokes([]);
      setDrawMode(false);
      setAnnotatingComment(null);
      return;
    }
    setSubmitting(true);
    setPendingStrokes([]);
    setDrawMode(false);
    setAnnotatingComment(null);
    commentsApi.updateAnnotations(token, parent.id, strokes).then(({ comment }) => {
      setComments(prev => prev.map(c => c.id === parent.id ? comment : c));
    }).catch(err => alert(err instanceof Error ? err.message : 'Failed to save annotation')).finally(() => setSubmitting(false));
  };

  // Discard pending strokes
  const handleUndoAnnotations = () => {
    setPendingStrokes([]);
    setDrawMode(false);
    setAnnotatingComment(null);
  };

  // Delete a single annotation from a comment (owner only)
  const handleDeleteAnnotation = async (commentId: string, remainingAnnotations: AnnotationData[]) => {
    if (!token) return;
    try {
      const { comment } = await commentsApi.updateAnnotations(token, commentId, remainingAnnotations);
      setComments(prev => prev.map(c => c.id === commentId ? comment : c));
    } catch {
      alert('Failed to delete annotation');
    }
  };

  const handleStatusUpdate = async (status: string) => {
    if (!token) return;
    setUpdatingStatus(true);
    try {
      const { asset: updated } = await assetsApi.updateStatus(token, assetId, status);
      setAsset(prev => prev ? { ...prev, status: updated.status } : prev);
      setShowApproval(false);
    } catch {
      alert('Failed to update status');
    } finally {
      setUpdatingStatus(false);
    }
  };

  const handleTimeUpdate = useCallback((time: number) => {
    setCurrentTime(time);
  }, []);

  const handleCommentSeek = useCallback((comment: Comment) => {
    const time = comment.timestamp ?? 0;
    setCurrentTime(time);
    if (mainVideoRef.current) {
      mainVideoRef.current.pause();
      mainVideoRef.current.currentTime = time;
    }
  }, []);

  const status = asset?.status ?? 'PENDING_REVIEW';
  const statusCfg = STATUS_CONFIG[status];

  const transcodeCfg = asset ? TRANSCODE_CONFIG[asset.transcodeStatus] : null;

  const videoUrl = asset?.hlsPath
    ? `${API_BASE}/uploads${asset.hlsPath}`
    : asset
      ? `${API_BASE}/uploads/${asset.filePath}`
      : '';

  const allComments = comments.flatMap(c => [c, ...(c.replies ?? [])]);
  const visibleComments = comments.filter(c => !c.deleted && (showResolved || !c.resolved));

  // Seek to previous/next comment (defined here so they can reference visibleComments)
  const handlePrevComment = useCallback(() => {
    const ts = visibleComments
      .filter(c => c.timestamp != null)
      .map(c => c.timestamp as number)
      .sort((a, b) => b - a);
    const prev = ts.find(t => t < currentTime - 0.3);
    if (prev !== undefined) handleCommentSeek({ timestamp: prev } as Comment);
  }, [visibleComments, currentTime, handleCommentSeek]);

  const handleNextComment = useCallback(() => {
    const ts = visibleComments
      .filter(c => c.timestamp != null)
      .map(c => c.timestamp as number)
      .sort((a, b) => a - b);
    const next = ts.find(t => t > currentTime + 0.3);
    if (next !== undefined) handleCommentSeek({ timestamp: next } as Comment);
  }, [visibleComments, currentTime, handleCommentSeek]);

  // Only main comments (not replies, not deleted) have annotations that should show on the video
  const visibleAnnotations = visibleComments
    .filter(c => !c.deleted)
    .flatMap(c =>
      (c.annotations ?? []).map(ann => ({ annotation: ann, timestamp: c.timestamp ?? 0 }))
    );

  // Annotations for the compare video — independent per-video data
  const compareVisibleComments = compareComments.filter(c => !c.deleted && (showResolved || !c.resolved));
  const compareVisibleAnnotations = compareVisibleComments
    .filter(c => !c.deleted)
    .flatMap(c =>
      (c.annotations ?? []).map(ann => ({ annotation: ann, timestamp: c.timestamp ?? 0 }))
    );

  if (loading) {
    return (
      <div className="h-screen flex items-center justify-center" style={{ background: 'var(--bg)' }}>
        <div className="flex items-center gap-3" style={{ color: 'var(--text-muted)' }}>
          <div className="w-5 h-5 rounded-full animate-spin"
               style={{ borderColor: '#6366F1', borderTopColor: 'transparent' }} />
          <span className="text-sm">Loading review…</span>
        </div>
      </div>
    );
  }

  if (!asset) return null;

  return (
    <div className="h-screen flex flex-col overflow-hidden" style={{ background: 'var(--bg)' }}>

      {/* ── Top bar ──────────────────────────────────────────── */}
      <header className="h-12 flex items-center px-4 gap-3 shrink-0"
              style={{ background: 'rgba(10,11,20,0.95)', borderBottom: '1px solid rgba(255,255,255,0.06)', zIndex: 50 }}>

        <button
          onClick={() => router.push(`/projects/${asset.projectId}`)}
          className="flex items-center gap-1.5 text-xs transition-colors shrink-0"
          style={{ color: 'var(--text-muted)' }}
        >
          <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
          </svg>
          <span className="hidden sm:inline">Back</span>
        </button>

        <div className="w-px h-5 shrink-0" style={{ background: 'rgba(255,255,255,0.08)' }} />

        <div className="flex-1 min-w-0">
          <h1 className="text-xs font-medium truncate" style={{ color: 'var(--text)' }}>{asset.title}</h1>
        </div>

        <span className="text-xs hidden sm:inline shrink-0" style={{ color: 'var(--text-subtle)' }}>
          {asset.project?.name}
        </span>

        <div className="w-px h-5 shrink-0" style={{ background: 'rgba(255,255,255,0.08)' }} />

        {/* Download */}
        <a
          href={`${API_BASE}/uploads/${asset.filePath}`}
          download={asset.filename}
          className="flex items-center gap-1.5 text-xs px-2.5 py-1 rounded-md transition-all shrink-0"
          style={{ color: '#60A5FA', background: 'rgba(96,165,250,0.08)' }}
          title="Download original video"
        >
          <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
          </svg>
          <span className="hidden sm:inline">Download</span>
        </a>

        <div className="w-px h-5 shrink-0" style={{ background: 'rgba(255,255,255,0.08)' }} />

        {/* Compare mode toggle */}
        <button
          onClick={() => {
            if (compareMode) {
              handleExitCompare();
            } else {
              setShowComparePicker(true);
              if (token && asset) {
                assetsApi.list(token, asset.projectId).then(({ assets }) => {
                  setProjectAssets(assets.filter(a => a.id !== assetId && a.transcodeStatus === 'COMPLETED'));
                }).catch(() => {});
              }
            }
          }}
          className={`flex items-center gap-1.5 text-xs px-2.5 py-1 rounded-md transition-all shrink-0 ${
            compareMode
              ? 'bg-indigo-600 text-white'
              : ''
          }`}
          style={!compareMode ? { color: '#818CF8', background: 'rgba(129,140,248,0.10)' } : {}}
          title="Side-by-side comparison"
        >
          <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" />
          </svg>
          <span className="hidden sm:inline">{compareMode ? 'Exit Compare' : 'Compare'}</span>
        </button>

        {/* Status selector */}
        <div className="relative shrink-0">
          <button
            onClick={() => setShowApproval(v => !v)}
            className="flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md transition-all"
            style={{ background: statusCfg.bgClass.replace('badge-', 'rgba(').replace('warning', '245,158,11,0.15)').replace('success', '34,197,94,0.15)').replace('danger', '239,68,68,0.15)'), color: statusCfg.colorClass }}
          >
            <span className={`status-dot ${statusCfg.dotClass}`} />
            <span className="hidden sm:inline">{statusCfg.label}</span>
            <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
              <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
            </svg>
          </button>

          {showApproval && (
            <>
              <div className="fixed inset-0 z-40" onClick={() => setShowApproval(false)} />
              <div className="absolute right-0 top-full mt-2 z-50 rounded-xl overflow-hidden"
                   style={{ background: '#1E2030', border: '1px solid rgba(255,255,255,0.10)', boxShadow: 'var(--shadow-panel)', minWidth: '200px' }}>
                {Object.entries(STATUS_CONFIG).map(([key, cfg]) => (
                  <button
                    key={key}
                    onClick={() => handleStatusUpdate(key)}
                    disabled={updatingStatus}
                    className="w-full flex items-center gap-2.5 px-4 py-2.5 text-xs transition-colors hover:bg-white/5"
                    style={{ color: key === status ? cfg.colorClass : 'var(--text)' }}
                  >
                    <span className={`status-dot ${cfg.dotClass}`} />
                    <span className="flex-1 text-left">{cfg.label}</span>
                    {key === status && (
                      <svg className="w-3.5 h-3.5" style={{ color: '#6366F1' }} fill="currentColor" viewBox="0 0 20 20">
                        <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
                      </svg>
                    )}
                  </button>
                ))}
              </div>
            </>
          )}
        </div>
      </header>

      {/* ── Compare picker modal ─────────────────────────────────────────────── */}
      {showComparePicker && (
        <>
          <div className="fixed inset-0 z-50" onClick={() => setShowComparePicker(false)} />
          <div
            className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 rounded-2xl overflow-hidden w-full max-w-md"
            style={{ background: '#1E2030', border: '1px solid rgba(255,255,255,0.10)', boxShadow: 'var(--shadow-modal)' }}
          >
            <div className="px-5 py-4 flex items-center justify-between" style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
              <h2 className="text-sm font-semibold" style={{ color: 'var(--text)' }}>Select video to compare</h2>
              <button onClick={() => setShowComparePicker(false)} className="w-7 h-7 flex items-center justify-center rounded-lg transition-colors hover:bg-white/10"
                style={{ color: 'var(--text-muted)' }}>
                <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>
            <div className="p-2 max-h-80 overflow-y-auto">
              {projectAssets.length === 0 ? (
                <p className="text-sm text-center py-8" style={{ color: 'var(--text-muted)' }}>
                  No other completed videos in this project.
                </p>
              ) : (
                projectAssets.map(a => (
                  <button
                    key={a.id}
                    onClick={() => handleCompareSelect(a)}
                    className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-left transition-colors hover:bg-white/5"
                  >
                    {a.thumbnail ? (
                      <img src={`${API_BASE}/uploads/${a.thumbnail}`} className="w-16 h-10 rounded-lg object-cover shrink-0" alt={a.title} />
                    ) : (
                      <div className="w-16 h-10 rounded-lg shrink-0 flex items-center justify-center" style={{ background: 'rgba(255,255,255,0.06)' }}>
                        <svg className="w-5 h-5" style={{ color: 'rgba(255,255,255,0.2)' }} fill="currentColor" viewBox="0 0 24 24">
                          <path d="M8 5v14l11-7z" />
                        </svg>
                      </div>
                    )}
                    <div className="flex-1 min-w-0">
                      <p className="text-sm font-medium truncate" style={{ color: 'var(--text)' }}>{a.title}</p>
                      <p className="text-xs" style={{ color: 'var(--text-muted)' }}>
                        {a.duration ? `${Math.floor(a.duration / 60)}:${Math.floor(a.duration % 60).toString().padStart(2, '0')}` : '—'}
                        {' · '}
                        {a.filename}
                      </p>
                    </div>
                  </button>
                ))
              )}
            </div>
          </div>
        </>
      )}

      {/* ── Body ───────────────────────────────────────────── */}
      {/* Landscape: side-by-side | Portrait: stacked (video top, comments bottom) */}
      <div
        className="flex flex-1 overflow-hidden"
        style={isPortrait
          ? { flexDirection: 'column', overflowY: 'auto' }
          : { flexDirection: 'row' }}
      >

        {/* Video area */}
        <div
          className="overflow-y-auto p-3 sm:p-4 flex flex-col gap-3 min-w-0"
          style={isPortrait
            ? { flex: 'none', width: '100%', minHeight: '45vh' }
            : { flex: 1, overflowY: 'auto' }}
        >

          {/* ── Side-by-side compare layout ───────────────────────── */}
          {compareMode ? (
            <div className="flex gap-2 w-full flex-1 min-h-0">
              {/* Main video + its comments */}
              <div className="flex-1 min-w-0 flex flex-col gap-0 min-h-0">
                {/* Annotation toggle */}
                <div className="flex items-center gap-2 mb-1 px-1">
                  <button
                    onClick={() => setShowMainAnnotations(v => !v)}
                    className="flex items-center gap-1.5 text-[11px] px-2 py-1 rounded-md transition-colors"
                    style={showMainAnnotations
                      ? { background: 'rgba(99,102,241,0.15)', color: '#818CF8' }
                      : { background: 'rgba(255,255,255,0.05)', color: 'var(--text-subtle)' }}
                    title={showMainAnnotations ? 'Hide annotations' : 'Show annotations'}
                  >
                    <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                      <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                    </svg>
                    Annot.
                  </button>
                </div>
                <div className="text-xs mb-1 px-1 truncate" style={{ color: 'rgba(255,255,255,0.5)' }}>
                  {asset.title}
                </div>
                <div className="flex-1 min-h-0 flex flex-col gap-0">
                  <VideoPlayer
                    src={videoUrl}
                    mimeType={asset.mimeType}
                    fps={fps}
                    comments={showMainAnnotations ? allComments : []}
                    visibleAnnotations={showMainAnnotations ? visibleAnnotations : []}
                    drawMode={drawMode}
                    drawTool={drawTool}
                    drawColor={drawColor}
                    onDrawModeChange={setDrawMode}
                    onDrawToolChange={setDrawTool}
                    onDrawColorChange={setDrawColor}
                    pendingStrokes={pendingStrokes}
                    onStrokeComplete={handleStrokeComplete}
                    onTimeUpdate={handleTimeUpdate}
                    onCommentClick={handleCommentSeek}
                    onPlayingChange={setPlaying}
                    onTimelineSeek={handleTimeUpdate}
                    externalCurrentTime={currentTime}
                    externalPlaying={playing}
                    videoRef={mainVideoRef}
                    onPrevComment={handlePrevComment}
                    onNextComment={handleNextComment}
                  />
                  {/* Comments below main video — full available height */}
                  <div className="mt-2 rounded-xl flex-1 min-h-0 flex flex-col overflow-hidden" style={{ background: 'rgba(10,11,20,0.80)', border: '1px solid rgba(255,255,255,0.06)' }}>
                    <div className="px-3 py-2 shrink-0 flex items-center gap-2" style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
                      <span className="text-xs font-medium" style={{ color: 'var(--text)' }}>
                        Comments
                      </span>
                      <span className="text-xs px-1.5 py-0.5 rounded-full" style={{ background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' }}>
                        {visibleComments.length}
                      </span>
                      <span className="font-mono text-[11px] ml-auto" style={{ color: '#818CF8' }}>
                        {formatTimecode(currentTime, fps, asset?.duration ?? 0)}
                      </span>
                    </div>
                    <div className="flex-1 overflow-y-auto scroll-area">
                      {visibleComments.length === 0 ? (
                        <p className="text-xs text-center py-4" style={{ color: 'var(--text-muted)' }}>No comments</p>
                      ) : (
                        visibleComments.map(comment => (
                          <div key={comment.id} className="px-3 py-2.5 flex items-start gap-2" style={{ borderBottom: '1px solid rgba(255,255,255,0.04)' }}>
                            <Avatar name={comment.user?.name ?? 'U'} size="xs" />
                            <div className="flex-1 min-w-0">
                              <div className="flex items-center gap-1.5 mb-0.5">
                                <span className="text-[11px] font-medium" style={{ color: 'var(--text)' }}>{comment.user?.name ?? 'Unknown'}</span>
                                {comment.timestamp != null && (
                                  <span className="text-[10px] font-mono px-1 rounded" style={{ background: 'rgba(99,102,241,0.10)', color: '#818CF8' }}>
                                    {formatTimecode(comment.timestamp, fps, asset?.duration ?? 0)}
                                  </span>
                                )}
                              </div>
                              <p className="text-[11px] leading-relaxed" style={{ color: 'var(--text-muted)' }}>{comment.content}</p>
                            </div>
                          </div>
                        ))
                      )}
                    </div>
                  </div>
                </div>
              </div>

              {/* Compare video + its comments — only show when durations match */}
              {compareAsset && !compareMismatch && (
                <div className="flex-1 min-w-0 flex flex-col gap-0 min-h-0">
                  {/* Annotation toggle */}
                  <div className="flex items-center gap-2 mb-1 px-1">
                    <button
                      onClick={() => setShowCompareAnnotations(v => !v)}
                      className="flex items-center gap-1.5 text-[11px] px-2 py-1 rounded-md transition-colors"
                      style={showCompareAnnotations
                        ? { background: 'rgba(99,102,241,0.15)', color: '#818CF8' }
                        : { background: 'rgba(255,255,255,0.05)', color: 'var(--text-subtle)' }}
                      title={showCompareAnnotations ? 'Hide annotations' : 'Show annotations'}
                    >
                      <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                        <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                      </svg>
                      Annot.
                    </button>
                  </div>
                  <div className="text-xs mb-1 px-1 truncate" style={{ color: 'rgba(255,255,255,0.5)' }}>
                    {compareAsset.title}
                  </div>
                  <div className="flex-1 min-h-0 flex flex-col gap-0">
                    <VideoPlayer
                      src={compareAsset.hlsPath ? `${API_BASE}/uploads${compareAsset.hlsPath}` : `${API_BASE}/uploads/${compareAsset.filePath}`}
                      mimeType={compareAsset.mimeType}
                      fps={compareAsset.fps ?? 30}
                      comments={showCompareAnnotations ? compareComments : []}
                      visibleAnnotations={showCompareAnnotations ? compareVisibleAnnotations : []}
                      drawMode={false}
                      drawTool={drawTool}
                      drawColor={drawColor}
                      onDrawModeChange={() => {}}
                      onDrawToolChange={() => {}}
                      onDrawColorChange={() => {}}
                      pendingStrokes={[]}
                      onStrokeComplete={() => {}}
                      onTimeUpdate={() => {}}
                      onCommentClick={() => {}}
                      isComparePlayer={true}
                      externalCurrentTime={currentTime}
                      externalPlaying={playing}
                    />
                    {/* Comments below compare video — full available height */}
                    <div className="mt-2 rounded-xl flex-1 min-h-0 flex flex-col overflow-hidden" style={{ background: 'rgba(10,11,20,0.80)', border: '1px solid rgba(255,255,255,0.06)' }}>
                      <div className="px-3 py-2 shrink-0 flex items-center gap-2" style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
                        <span className="text-xs font-medium" style={{ color: 'var(--text)' }}>
                          Comments
                        </span>
                        <span className="text-xs px-1.5 py-0.5 rounded-full" style={{ background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' }}>
                          {compareVisibleComments.length}
                        </span>
                      </div>
                      <div className="flex-1 overflow-y-auto scroll-area">
                        {compareVisibleComments.length === 0 ? (
                          <p className="text-xs text-center py-4" style={{ color: 'var(--text-muted)' }}>No comments</p>
                        ) : (
                          compareVisibleComments.map(comment => (
                            <div key={comment.id} className="px-3 py-2.5 flex items-start gap-2" style={{ borderBottom: '1px solid rgba(255,255,255,0.04)' }}>
                              <Avatar name={comment.user?.name ?? 'U'} size="xs" />
                              <div className="flex-1 min-w-0">
                                <div className="flex items-center gap-1.5 mb-0.5">
                                  <span className="text-[11px] font-medium" style={{ color: 'var(--text)' }}>{comment.user?.name ?? 'Unknown'}</span>
                                  {comment.timestamp != null && (
                                    <span className="text-[10px] font-mono px-1 rounded" style={{ background: 'rgba(99,102,241,0.10)', color: '#818CF8' }}>
                                      {formatTimecode(comment.timestamp, fps, asset?.duration ?? 0)}
                                    </span>
                                  )}
                                </div>
                                <p className="text-[11px] leading-relaxed" style={{ color: 'var(--text-muted)' }}>{comment.content}</p>
                              </div>
                            </div>
                          ))
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              )}
            </div>
          ) : (
          /* ── Normal single-video layout ─────────────────────────── */
          <VideoPlayer
            src={videoUrl}
            mimeType={asset.mimeType}
            fps={fps}
            comments={allComments}
            visibleAnnotations={visibleAnnotations}
            drawMode={drawMode}
            drawTool={drawTool}
            drawColor={drawColor}
            onDrawModeChange={setDrawMode}
            onDrawToolChange={setDrawTool}
            onDrawColorChange={setDrawColor}
            pendingStrokes={pendingStrokes}
            onStrokeComplete={handleStrokeComplete}
            onTimeUpdate={handleTimeUpdate}
            onCommentClick={handleCommentSeek}
            onPlayingChange={setPlaying}
            videoRef={mainVideoRef}
            onPrevComment={handlePrevComment}
            onNextComment={handleNextComment}
          />
          )}

          {/* ── Compare mismatch warning ─────────────────────────── */}
          {compareMode && compareMismatch && (
            <div className="rounded-xl px-4 py-3 text-xs flex items-center gap-3"
                 style={{ background: 'rgba(251,191,36,0.10)', border: '1px solid rgba(251,191,36,0.25)', color: '#FCD34D' }}>
              <svg className="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                <path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
              </svg>
              <span className="flex-1">{compareMismatch}</span>
              <button
                onClick={handleExitCompare}
                className="shrink-0 px-2 py-1 rounded-md transition-colors"
                style={{ background: 'rgba(251,191,36,0.15)', color: '#FCD34D' }}
              >
                Cancel
              </button>
            </div>
          )}

          {/* Transcode status overlay — shown when video is not ready */}
          {transcodeCfg && asset.transcodeStatus !== 'COMPLETED' && (
            <div className="mt-3 rounded-xl p-4 flex items-center gap-4"
                 style={{ background: transcodeCfg.bg, border: `1px solid ${transcodeCfg.color}30` }}>
              {transcodeCfg.spinner ? (
                <div className="w-8 h-8 rounded-full animate-spin shrink-0"
                     style={{ borderColor: transcodeCfg.color, borderTopColor: 'transparent', borderWidth: '2.5px' }} />
              ) : asset.transcodeStatus === 'FAILED' ? (
                <div className="w-8 h-8 rounded-full flex items-center justify-center shrink-0"
                     style={{ background: 'rgba(248,113,113,0.15)' }}>
                  <svg className="w-4 h-4" style={{ color: '#F87171' }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
                  </svg>
                </div>
              ) : (
                <div className="w-8 h-8 rounded-full flex items-center justify-center shrink-0"
                     style={{ background: 'rgba(251,191,36,0.15)' }}>
                  <svg className="w-4 h-4" style={{ color: '#FBBF24' }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
                  </svg>
                </div>
              )}

              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2 mb-1">
                  <span className="text-sm font-medium" style={{ color: transcodeCfg.color }}>
                    {transcodeCfg.label}
                  </span>
                  {asset.transcodeStatus === 'PROCESSING' && asset.transcodeProgress > 0 && (
                    <span className="text-xs font-mono" style={{ color: transcodeCfg.color }}>
                      {asset.transcodeProgress}%
                    </span>
                  )}
                </div>
                {asset.transcodeStatus === 'PROCESSING' && (
                  <div className="w-full h-1 rounded-full overflow-hidden" style={{ background: 'rgba(255,255,255,0.08)' }}>
                    <div
                      className="h-full rounded-full transition-all duration-500"
                      style={{ width: `${asset.transcodeProgress}%`, background: transcodeCfg.color }}
                    />
                  </div>
                )}
                {asset.transcodeStatus === 'FAILED' && asset.transcodeError && (
                  <p className="text-xs mt-1" style={{ color: '#F87171' }}>
                    {asset.transcodeError}
                  </p>
                )}
                {asset.transcodeStatus === 'UNSUPPORTED_CODEC' && (
                  <p className="text-xs mt-1" style={{ color: '#FB923C' }}>
                    {asset.codec ? `Source codec "${asset.codec.toUpperCase()}" — will re-encode to H.264/AAC` : 'Re-encoding to browser-compatible format…'}
                  </p>
                )}
                {asset.transcodeStatus === 'PROCESSING' && asset.codec && (
                  <p className="text-xs mt-1" style={{ color: '#94A3B8' }}>
                    Converting from {asset.codec.toUpperCase()} → H.264/AAC
                  </p>
                )}
                {asset.transcodeStatus === 'UPLOADING' && (
                  <p className="text-xs mt-1" style={{ color: '#94A3B8' }}>
                    Video uploaded — queued for processing
                  </p>
                )}
              </div>
            </div>
          )}

          {/* Keyboard shortcuts */}
          {!compareMode && (
          <div className="flex flex-wrap gap-3 text-xs shrink-0 hidden sm:flex" style={{ color: 'var(--text-subtle)' }}>
            <span><kbd className="px-1.5 py-0.5 rounded text-[10px]" style={{ background: 'rgba(255,255,255,0.06)' }}>Space</kbd> play/pause</span>
            <span><kbd className="px-1.5 py-0.5 rounded text-[10px]" style={{ background: 'rgba(255,255,255,0.06)' }}>←</kbd><kbd className="px-1.5 py-0.5 rounded text-[10px] ml-0.5" style={{ background: 'rgba(255,255,255,0.06)' }}>→</kbd> ±1 frame <kbd className="px-1.5 py-0.5 rounded text-[10px]" style={{ background: 'rgba(255,255,255,0.06)' }}>⇧←</kbd><kbd className="px-1.5 py-0.5 rounded text-[10px] ml-0.5" style={{ background: 'rgba(255,255,255,0.06)' }}>⇧→</kbd> ±1s</span>
            <span><kbd className="px-1.5 py-0.5 rounded text-[10px]" style={{ background: 'rgba(255,255,255,0.06)' }}>C</kbd> draw mode</span>
            <span><kbd className="px-1.5 py-0.5 rounded text-[10px]" style={{ background: 'rgba(255,255,255,0.06)' }}>Esc</kbd> exit draw</span>
            <span className="font-mono text-[11px]">{formatTimecode(currentTime, fps, asset?.duration ?? 0)}</span>
          </div>
          )}
        </div>

        {/* Resize handle — only shown in landscape, hidden in compare mode */}
        {!isPortrait && !compareMode && (
          <div className="resize-handle" onMouseDown={handleResizeStart} style={{ width: '4px' }} />
        )}

        {/* ── Comment panel — hidden in compare mode (comments are below each video) ── */}
        {!compareMode && (
        <div
          ref={panelRef}
          className="flex flex-col overflow-hidden shrink-0"
          style={isPortrait
            ? {
                flex: 1,
                width: '100%',
                minHeight: '55vh',
                background: 'rgba(10,11,20,0.98)',
                borderTop: '1px solid rgba(255,255,255,0.06)',
              }
            : {
                width: panelWidth,
                background: 'rgba(10,11,20,0.98)',
                borderLeft: '1px solid rgba(255,255,255,0.06)',
              }}
        >
          {/* Panel header */}
          <div className="px-3 sm:px-4 py-2.5 sm:py-3 flex items-center justify-between shrink-0"
               style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
            <div className="flex items-center gap-2">
              <h2 className="text-[13px] sm:text-sm font-semibold" style={{ color: 'var(--text)' }}>Comments</h2>
              <span className="text-xs px-1.5 py-0.5 rounded-full"
                    style={{ background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' }}>
                {comments.length}
              </span>
            </div>
            <div className="flex items-center gap-2">
              <span className="font-mono text-[11px] sm:text-xs hidden sm:inline" style={{ color: '#818CF8' }}>
                {formatTimecode(currentTime, fps, asset?.duration ?? 0)}
              </span>
              <button
                onClick={() => setShowResolved(v => !v)}
                className={`text-[11px] px-2 py-0.5 rounded-md transition-colors ${showResolved ? 'bg-indigo-600 text-white' : ''}`}
                style={!showResolved ? { background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' } : {}}
              >
                {showResolved ? 'Hide resolved' : 'Show resolved'}
              </button>
              {compareMode && (
                <span className="text-[11px] px-2 py-0.5 rounded-md" style={{ background: 'rgba(99,102,241,0.15)', color: '#818CF8' }}>
                  Compare mode
                </span>
              )}
            </div>
          </div>

          {/* Drawing mode banner */}
          {drawMode && (
            <div className="px-4 py-2 shrink-0 flex items-center gap-2"
                 style={{ background: 'rgba(59,130,246,0.12)', borderBottom: '1px solid rgba(59,130,246,0.2)' }}>
              <svg className="w-4 h-4 shrink-0" style={{ color: '#818CF8' }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
              </svg>
              <span className="text-xs flex-1" style={{ color: '#818CF8' }}>
                {annotatingComment
                  ? `Drawing annotation on "${annotatingComment.user?.name}" — ${pendingStrokes.length}/${MAX_ANNOTATIONS} strokes`
                  : `Drawing on video — ${pendingStrokes.length}/${MAX_ANNOTATIONS} strokes`}
              </span>
              <div className="flex items-center gap-1.5">
                <button
                  onClick={handleUndoAnnotations}
                  className="text-xs px-2 py-0.5 rounded transition-colors"
                  style={{ background: 'rgba(239,68,68,0.15)', color: '#FCA5A5' }}
                >
                  Undo all
                </button>
                <button
                  onClick={handleSaveAnnotations}
                  disabled={submitting || pendingStrokes.length === 0}
                  className="text-xs px-2 py-0.5 rounded transition-colors disabled:opacity-40"
                  style={{ background: 'rgba(34,197,94,0.15)', color: '#86EFAC' }}
                >
                  {submitting ? 'Saving…' : 'Save'}
                </button>
              </div>
            </div>
          )}

          {/* Comment list */}
          <div className="flex-1 overflow-y-auto scroll-area">
            {visibleComments.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-16 px-4 text-center">
                <div className="w-12 h-12 rounded-2xl flex items-center justify-center mb-3"
                     style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.12)' }}>
                  <svg className="w-6 h-6" style={{ color: '#6366F1' }} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z" />
                  </svg>
                </div>
                <p className="text-sm font-medium mb-1" style={{ color: 'var(--text)' }}>No comments yet</p>
                <p className="text-xs leading-relaxed" style={{ color: 'var(--text-muted)' }}>
                  Add a comment below or click <strong>Add annotation</strong> on an existing comment
                </p>
              </div>
            ) : (
              <div>
                {visibleComments.map(comment => (
                  <CommentItem
                    key={comment.id}
                    comment={comment}
                    currentUserId={user?.id ?? ''}
                    fps={fps}
                    duration={asset?.duration ?? 0}
                    canComment={canComment}
                    isProjectAdmin={isProjectAdmin}
                    isProjectOwner={isProjectOwner ?? false}
                    onTimestampClick={handleCommentSeek}
                    onReply={() => { setReplyTo(comment); }}
                    onResolve={(action) => handleResolve(comment.id, action)}
                    onRequestResolve={() => handleRequestResolve(comment.id)}
                    onDeleteSelf={() => handleDeleteComment(comment.id)}
                    onDelete={(id) => handleDeleteComment(id)}
                    onAddAnnotation={() => handleAddAnnotationClick(comment)}
                    onDeleteAnnotation={(anns) => handleDeleteAnnotation(comment.id, anns)}
                    onRestore={handleRestoreComment}
                  />
                ))}
              </div>
            )}
          </div>

          {/* New comment / reply input */}
          <div className="shrink-0 p-4"
               style={{ borderTop: '1px solid rgba(255,255,255,0.06)', background: 'rgba(10,11,20,0.80)' }}>
            {replyTo && (
              <div className="flex items-center gap-2 mb-2 text-xs" style={{ color: 'var(--text-muted)' }}>
                <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
                </svg>
                Replying to {replyTo.user?.name}
                <button onClick={() => setReplyTo(null)} className="ml-auto" style={{ color: 'var(--text-subtle)' }}>
                  <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                  </svg>
                </button>
              </div>
            )}

            {/* Pending strokes indicator */}
            {pendingStrokes.length > 0 && (
              <div className="flex items-center gap-2 mb-2 text-xs" style={{ color: '#818CF8' }}>
                <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                </svg>
                {pendingStrokes.length} stroke{pendingStrokes.length !== 1 ? 's' : ''} ready
                {annotatingComment ? ` → annotation on "${annotatingComment.user?.name}"` : ' → will be saved as new comment'}
                <button onClick={handleUndoAnnotations} className="ml-auto text-xs" style={{ color: '#FCA5A5' }}>Undo</button>
              </div>
            )}

            <form
              onSubmit={e => {
                e.preventDefault();
                if (newComment.trim() || pendingStrokes.length > 0) {
                  handleAddComment(newComment, currentTime, pendingStrokes.length > 0 ? pendingStrokes : undefined);
                }
              }}
              className="flex gap-2"
            >
              <Avatar name={user?.name ?? 'U'} size="sm" />
              <div className="flex-1 flex gap-2">
                <textarea
                  className="input flex-1"
                  value={compareMode ? '' : newComment}
                  onChange={e => setNewComment(e.target.value)}
                  placeholder={compareMode ? 'Comments disabled in compare mode' : replyTo ? 'Write a reply…' : 'Add a comment…'}
                  disabled={compareMode}
                  readOnly={compareMode}
                  rows={1}
                  style={{ resize: 'none', overflow: 'hidden' }}
                  onKeyDown={e => {
                    if (e.key === 'Enter' && !e.shiftKey) {
                      e.preventDefault();
                      if (newComment.trim() || pendingStrokes.length > 0) {
                        handleAddComment(newComment, currentTime, pendingStrokes.length > 0 ? pendingStrokes : undefined);
                      }
                    }
                  }}
                />
                <button
                  type="submit"
                  disabled={submitting || (!newComment.trim() && pendingStrokes.length === 0)}
                  className="btn btn-primary btn-sm px-3"
                >
                  {submitting ? (
                    <div className="w-3.5 h-3.5 rounded-full animate-spin"
                         style={{ borderColor: '#fff', borderTopColor: 'transparent' }} />
                  ) : (
                    <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                      <path strokeLinecap="round" strokeLinejoin="round" d="M6 12h12M6 12l4-4M6 12l4 4" />
                    </svg>
                  )}
                </button>
              </div>
            </form>
          </div>
        </div>
        )}
      </div>
    </div>
  );
}

// ── CommentItem ─────────────────────────────────────────────────────────────
function CommentItem({
  comment,
  currentUserId,
  fps,
  duration,
  canComment,
  isProjectAdmin,
  isProjectOwner,
  onTimestampClick,
  onReply,
  onResolve,
  onRequestResolve,
  onDeleteSelf,
  onDelete,
  onAddAnnotation,
  onDeleteAnnotation,
  onRestore,
}: {
  comment: Comment;
  currentUserId: string;
  fps: number;
  duration: number;
  canComment: boolean | undefined;
  isProjectAdmin: boolean;
  isProjectOwner: boolean;
  onTimestampClick: (c: Comment) => void;
  onReply: () => void;
  onResolve: (action: 'approve' | 'reject') => void;
  onRequestResolve: () => void;
  onDeleteSelf: () => void;
  onDelete: (id: string) => void;
  onAddAnnotation: () => void;
  onDeleteAnnotation: (annotations: AnnotationData[]) => void;
  onRestore: (id: string) => void;
}) {
  const isOwner = comment.userId === currentUserId;
  const isCommentAuthor = comment.userId === currentUserId;
  const name = comment.user?.name ?? 'Unknown';
  const isReply = !!comment.parentId;
  const annotations = comment.annotations ?? [];
  const canAddMore = annotations.length < MAX_ANNOTATIONS;
  const isDeleted = !!comment.deleted;
  const canRestore = !isDeleted && (isProjectOwner || isProjectAdmin);

  // Resolve state machine
  const isResolved = comment.resolveStatus === 'RESOLVED';
  const isPending = comment.resolveStatus === 'PENDING_APPROVAL';
  const canApprove = isCommentAuthor || isProjectAdmin;
  const canRequest = canComment && !isResolved && !isPending && !isCommentAuthor;
  const canReopen = isResolved && canApprove;

  return (
    <div
      className="p-4 animate-fade-in"
      style={{
        opacity: isDeleted ? 0.45 : isResolved ? 0.55 : 1,
        paddingLeft: isReply ? '2.5rem' : undefined,
        borderLeft: isDeleted ? '2px solid rgba(239,68,68,0.3)' : undefined,
      }}
    >
      <div className="flex gap-2.5">
        <Avatar name={name} size="sm" />

        <div className="flex-1 min-w-0">
          {/* Meta row */}
          <div className="flex items-center gap-2 mb-1 flex-wrap">
            <span className="text-xs font-medium" style={{ color: 'var(--text)' }}>{name}</span>
            {comment.timestamp != null && (
              <button
                onClick={() => onTimestampClick(comment)}
                className="text-xs px-1.5 py-0.5 rounded font-mono transition-colors hover:bg-indigo-600/20"
                style={{ background: 'rgba(99,102,241,0.10)', color: '#818CF8', fontSize: '11px' }}
              >
                {formatTimecode(comment.timestamp, fps, duration)}
              </button>
            )}
            {isPending && (
              <span className="text-xs px-1.5 py-0.5 rounded"
                    style={{ background: 'rgba(251,191,36,0.12)', color: '#FCD34D' }}>
                Pending approval
              </span>
            )}
            {isResolved && (
              <span className="text-xs px-1.5 py-0.5 rounded"
                    style={{ background: 'rgba(34,197,94,0.10)', color: '#86EFAC' }}>
                Approved
              </span>
            )}
            {isResolved && comment.resolvedBy && (
              <span className="text-xs" style={{ color: 'var(--text-subtle)' }}>
                by {comment.resolvedBy.name}
              </span>
            )}
            <span className="text-xs ml-auto" style={{ color: 'var(--text-subtle)' }}>
              {new Date(comment.createdAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
            </span>
          </div>

          {/* Annotation preview badges */}
          {annotations.length > 0 && (
            <div className="flex flex-wrap gap-1 mb-2">
              {annotations.map((ann, i) => (
                <div
                  key={i}
                  className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded"
                  style={{ background: `${ann.color}20`, color: ann.color, border: `1px solid ${ann.color}40` }}
                >
                  <svg className="w-2.5 h-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                  </svg>
                  {ann.type}
                  {isOwner && (
                    <button
                      onClick={() => {
                        const remaining = annotations.filter((_, j) => j !== i);
                        onDeleteAnnotation(remaining);
                      }}
                      className="ml-0.5 hover:opacity-70 transition-opacity"
                      title="Delete this annotation"
                    >
                      <svg className="w-2.5 h-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                        <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                      </svg>
                    </button>
                  )}
                </div>
              ))}
            </div>
          )}

          {/* Content */}
          <p className="text-[13px] sm:text-sm leading-relaxed mb-2" style={{ color: 'var(--text-muted)' }}>
            {comment.content}
          </p>

          {/* Actions */}
          <div className="flex items-center gap-1">
            {/* Restore button for soft-deleted comments — project owner/ADMIN only */}
            {isDeleted && (isProjectOwner || isProjectAdmin) && (
              <button
                onClick={() => onRestore(comment.id)}
                className="text-xs px-2 py-1 rounded-md transition-colors"
                style={{ color: '#86EFAC', background: 'rgba(34,197,94,0.10)' }}
                title="Restore this comment"
              >
                <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                </svg>
                Restore
              </button>
            )}

            {!isReply && !isDeleted && (
              <button
                onClick={onAddAnnotation}
                disabled={!canAddMore}
                className="text-xs px-2 py-1 rounded-md transition-colors disabled:opacity-30"
                style={{ color: '#818CF8' }}
                title={canAddMore ? `Add annotation (${annotations.length}/${MAX_ANNOTATIONS})` : `Max ${MAX_ANNOTATIONS} annotations reached`}
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                </svg>
              </button>
            )}
            {!isReply && !isDeleted && (
              <button
                onClick={onReply}
                className="text-xs px-2 py-1 rounded-md transition-colors"
                style={{ color: 'var(--text-muted)' }}
                title="Reply"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
                </svg>
              </button>
            )}
            {!isReply && (
              <button
                onClick={onReply}
                className="text-xs px-2 py-1 rounded-md transition-colors"
                style={{ color: 'var(--text-muted)' }}
                title="Reply"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
                </svg>
              </button>
            )}

            {/* Resolve / approval workflow buttons */}
            {!isReply && !isDeleted && !isResolved && !isPending && (
              <>
                {canRequest ? (
                  <button
                    onClick={onRequestResolve}
                    className="text-xs px-2 py-1 rounded-md transition-colors"
                    style={{ color: '#6366F1' }}
                    title="Request resolve approval"
                  >
                    <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                      <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
                    </svg>
                    Request resolve
                  </button>
                ) : (
                  <span
                    className="text-xs px-2 py-1 opacity-30"
                    style={{ color: '#6366F1' }}
                    title={!canComment ? 'Viewers cannot request resolve' : isCommentAuthor ? 'Cannot resolve your own comment' : undefined}
                  >
                    <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                      <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
                    </svg>
                    Request resolve
                  </span>
                )}
              </>
            )}

            {isPending && canApprove && !isReply && !isDeleted && (
              <>
                <button
                  onClick={() => onResolve('approve')}
                  className="text-xs px-2 py-1 rounded-md transition-colors"
                  style={{ color: '#86EFAC' }}
                  title={`Approve (by ${comment.requestedBy?.name ?? 'someone'})`}
                >
                  <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
                  </svg>
                  Approve
                </button>
                <button
                  onClick={() => onResolve('reject')}
                  className="text-xs px-2 py-1 rounded-md transition-colors"
                  style={{ color: '#FCA5A5' }}
                  title="Reject resolve request"
                >
                  <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                    <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                  </svg>
                  Reject
                </button>
              </>
            )}

            {isPending && !canApprove && !isReply && !isDeleted && (
              <span className="text-xs px-2 py-1 opacity-40" style={{ color: '#FCD34D' }} title="Awaiting approval">
                <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                </svg>
                Awaiting approval
              </span>
            )}

            {canReopen && !isReply && !isDeleted && (
              <button
                onClick={() => onResolve('reject')}
                className="text-xs px-2 py-1 rounded-md transition-colors"
                style={{ color: '#86EFAC' }}
                title="Reopen comment"
              >
                <svg className="w-3.5 h-3.5 inline-block mr-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                </svg>
                Reopen
              </button>
            )}

            {isOwner && !isDeleted && (
              <button
                onClick={onDeleteSelf}
                className="text-xs px-2 py-1 rounded-md transition-colors"
                style={{ color: 'var(--text-subtle)' }}
                title="Hide comment"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                </svg>
              </button>
            )}
          </div>

          {/* Replies */}
          {comment.replies && comment.replies.length > 0 && (
            <div className="mt-3 space-y-3">
              {comment.replies.map(reply => (
                <ReplyItem
                  key={reply.id}
                  comment={reply}
                  isOwner={reply.userId === currentUserId}
                  onDelete={() => onDelete(reply.id)}
                />
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ── ReplyItem ──────────────────────────────────────────────────────────────
// Replies have no resolve, no annotation, no timestamp — just content + delete
function ReplyItem({
  comment,
  isOwner,
  onDelete,
}: {
  comment: Comment;
  isOwner: boolean;
  onDelete: (id: string) => void;
}) {
  return (
    <div className="flex gap-2.5 animate-fade-in">
      <Avatar name={comment.user?.name ?? 'U'} size="sm" />
      <div className="flex-1 min-w-0">
        <div className="flex items-center gap-2 mb-0.5">
          <span className="text-xs font-medium" style={{ color: 'var(--text)' }}>
            {comment.user?.name ?? 'Unknown'}
          </span>
          <span className="text-xs ml-auto" style={{ color: 'var(--text-subtle)' }}>
            {new Date(comment.createdAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
          </span>
        </div>
        <p className="text-sm leading-relaxed" style={{ color: 'var(--text-muted)' }}>
          {comment.content}
        </p>
        {isOwner && (
          <button
            onClick={() => onDelete(comment.id)}
            className="text-xs mt-1 transition-colors"
            style={{ color: 'var(--text-subtle)' }}
            title="Delete reply"
          >
            Delete
          </button>
        )}
      </div>
    </div>
  );
}
